package com.bluefox.modules.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.bluefox.utils.QueryHelp;
import com.bluefox.utils.UpdateUtil;
import com.bluefox.modules.system.criteria.MenuQueryCriteria;
import com.bluefox.modules.system.domain.SysMenu;
import com.bluefox.modules.system.domain.vo.MenuMetaVo;
import com.bluefox.modules.system.domain.vo.MenuVo;
import com.bluefox.modules.system.domain.vo.TreeSelect;
import com.bluefox.modules.system.repository.SysMenuRepository;
import com.bluefox.modules.system.service.dto.RoleSmallDto;
import com.bluefox.modules.system.service.dto.SysMenuDto;
import com.bluefox.modules.system.service.mapper.SysMenuMapper;
import com.bluefox.modules.system.service.SysMenuService;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import org.springframework.transaction.annotation.Transactional;

/**
 * (SysMenu)表服务实现类
 *
 * @author sunfeng
 * @since 2020-04-17 15:01:44
 */
@Service("sysMenuService")
public class SysMenuServiceImpl implements SysMenuService {
    @Resource
    private SysMenuRepository sysMenuRepository;

    @Resource
    private SysMenuMapper sysMenuMapper;


    @Override
    public List<SysMenuDto> queryAll(MenuQueryCriteria criteria, boolean isQuery) throws Exception {
        Sort sort = new Sort(Sort.Direction.ASC, "orderNum");

        List<SysMenu> sysMenuList = sysMenuRepository.findAll((root, criteriaQuery, criteriaBuilder) ->
                QueryHelp.getPredicate(root, criteria, criteriaBuilder), sort);
        return sysMenuMapper.toDto(sysMenuList);
    }

    @Override
    public SysMenuDto queryById(Long menuId) {
        return this.sysMenuMapper.toDto(this.sysMenuRepository.getOne(menuId));
    }

    @Override
    public List<SysMenuDto> findAll() {

        return this.sysMenuMapper.toDto(this.sysMenuRepository.findAll());

    }

    /**
     * 根据用户 userId 查询菜单
     *
     * @param userId
     * @return
     */
    @Override
    public Collection<? extends String> selectMenuPermsByUserId(Long userId) {
        return this.sysMenuRepository.findPermsSet(userId);

    }

    @Override
    public List<SysMenuDto> findByRoles(List<RoleSmallDto> roles) {
        Set<Long> roleIds = roles.stream().map(RoleSmallDto::getId).collect(Collectors.toSet());


        LinkedHashSet<SysMenu> menus = sysMenuRepository.findBySysRoles_IdInAndMenuTypeNotOrderByOrderNumAsc(roleIds, "F");
        return menus.stream().map(sysMenuMapper::toDto).collect(Collectors.toList());
    }

    /**
     * 将菜单列表转换成菜单树
     *
     * @param menuDtoList
     * @return
     */
    @Override
    public Map<String, Object> buildTree(List<SysMenuDto> menuDtoList) {
        List<SysMenuDto> trees = new ArrayList<>();
        Set<Long> ids = new HashSet<>();

        for (SysMenuDto menuDTO : menuDtoList) {
            if (menuDTO.getParentId() == 0) {
                trees.add(menuDTO);
            }
            for (SysMenuDto it : menuDtoList) {
                if (it.getParentId().equals(menuDTO.getId())) {
                    if (menuDTO.getChildren() == null) {
                        menuDTO.setChildren(new ArrayList<>());
                    }
                    menuDTO.getChildren().add(it);
                    ids.add(it.getId());
                }
            }
        }
        Map<String, Object> map = new HashMap<>(2);
        if (trees.size() == 0) {
            trees = menuDtoList.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList());
        }
        map.put("content", trees);
        map.put("totalElements", menuDtoList.size());
        return map;
    }

    /**
     * 组装菜单组件
     *
     * @param menuDtos /
     * @return
     */
    @Override
    public List<MenuVo> buildMenus(List<SysMenuDto> menuDtos) {
        List<MenuVo> list = new LinkedList<>();
        menuDtos.forEach(menuDTO -> {
                    if (menuDTO != null) {
                        List<SysMenuDto> menuDtoList = menuDTO.getChildren();
                        MenuVo menuVo = new MenuVo();
                        // 设置组件名字
                        menuVo.setName(ObjectUtil.isNotEmpty(menuDTO.getComponentName()) ? menuDTO.getComponentName() : menuDTO.getMenuName());
                        // 设置一级目录 一级目录需要加斜杠，不然会报警告
                        menuVo.setPath(menuDTO.getParentId() == 0 ? "/" + menuDTO.getPath() : menuDTO.getPath());
                        //是否隐藏
                        menuVo.setHidden(!menuDTO.getVisible().equals("0"));
                        // 如果不是外链
                        if (menuDTO.getIsFrame().equals("1")) {
                            if (menuDTO.getParentId() == 0) {
                                menuVo.setComponent(StrUtil.isEmpty(menuDTO.getComponent()) ? "Layout" : menuDTO.getComponent());
                            } else if (!StrUtil.isEmpty(menuDTO.getComponent())) {
                                menuVo.setComponent(menuDTO.getComponent());
                            }
                        }
                        // 设置元数据
                        menuVo.setMeta(new MenuMetaVo(menuDTO.getMenuName(), menuDTO.getIcon(), !menuDTO.getVisible().equals("0")));
                        // 如果有有子节点
                        if (menuDtoList != null && menuDtoList.size() != 0) {
                            menuVo.setAlwaysShow(true);
                            menuVo.setRedirect("noredirect");
                            menuVo.setChildren(buildMenus(menuDtoList));
                            // 处理是一级菜单并且没有子菜单的情况
                        } else if (menuDTO.getParentId() == 0) {
                            MenuVo menuVo1 = new MenuVo();
                            menuVo1.setMeta(menuVo.getMeta());
                            // 非外链
                            if (!menuDTO.getIsFrame().equals("0")) {
                                menuVo1.setPath("index");
                                menuVo1.setName(menuVo.getName());
                                menuVo1.setComponent(menuVo.getComponent());
                            } else {
                                menuVo1.setPath(menuDTO.getPath());
                            }
                            menuVo.setName(null);
                            menuVo.setMeta(null);
                            menuVo.setComponent("Layout");
                            List<MenuVo> list1 = new ArrayList<>();
                            list1.add(menuVo1);
                            menuVo.setChildren(list1);
                        }
                        list.add(menuVo);
                    }
                }
        );
        return list;
    }

    /**
     * 将菜单列表构建成菜单树  select属性
     *
     * @param menus
     * @return
     */
    @Override
    public List<TreeSelect> buildMenuTreeSelect(List<SysMenuDto> menus) {

        List<SysMenuDto> menuTree = getMenuTree(menus);

        return menuTree.stream().map(TreeSelect::new).collect(Collectors.toList());
    }


    /**
     * 根据父id获取菜单
     *
     * @param pid
     * @return
     */
    @Override
    public List<SysMenuDto> findByPid(long pid) {
        return this.sysMenuMapper.toDto(sysMenuRepository.findByParentId(pid));
    }

    /**
     * 将菜单列表 构建成菜单树 全属性
     *
     * @param menus
     * @return
     */
    @Override
    public List<SysMenuDto> getMenuTree(List<SysMenuDto> menus) {
        List<SysMenuDto> list = new LinkedList<>();
        menus.forEach(sysMenuDto -> {
            if (sysMenuDto != null) {
                List<SysMenuDto> menuDtoList = findByPid(sysMenuDto.getId());
                sysMenuDto.setChildren(getMenuTree(menuDtoList));
                sysMenuDto.setLabel(sysMenuDto.getMenuName());
                list.add(sysMenuDto);
            }
        });
        return list;
    }

    /**
     * 根据角色id获取菜单列表
     *
     * @param roleId
     * @return
     */
    @Override
    public List<SysMenuDto> selectMenuListByRoleId(Long roleId) {
        Set<Long> roleIds = new HashSet<>();
        roleIds.add(roleId);
        LinkedHashSet<SysMenu> sysMenuSet = sysMenuRepository.findBySysRoles_IdInAndMenuTypeNotOrderByOrderNumAsc(roleIds, "");
        List<SysMenuDto> sysMenus = sysMenuSet.stream().map(sysMenuMapper::toDto).collect(Collectors.toList());
        return getMenuTree(sysMenus);
    }

    /**
     * @param menuIds
     */
    @Override
    @Transactional
    public void deleteMenuByIds(Long[] menuIds) {

    }


    @Override
    public SysMenuDto insert(SysMenuDto sysMenuDto) {

        SysMenu sysMenu = new SysMenu();

        UpdateUtil.copyNullProperties(sysMenuDto, sysMenu);

        return this.sysMenuMapper.toDto(
                this.sysMenuRepository.save(sysMenu));
    }


    @Override
    public SysMenuDto update(SysMenuDto sysMenuDto) {

        SysMenu sysMenu = sysMenuRepository.findById(sysMenuDto.getId()).get();

        UpdateUtil.copyNullProperties(sysMenuDto, sysMenu);

        return this.sysMenuMapper.toDto(
                this.sysMenuRepository.save(sysMenu));
    }


    @Override
    public boolean deleteById(Long menuId) {

        try {
            this.sysMenuRepository.deleteById(menuId);
        } catch (Exception ex) {
            return false;
        }
        return true;

    }
}
